package config

import (
	"sync"
	"zstackgo/java"
	"zstackgo/pkg/core/cloudbus"
	"zstackgo/pkg/core/componentloader"
	"zstackgo/pkg/core/db"
	"zstackgo/pkg/core/errorcode"
	"zstackgo/spring"

	"github.com/meilihao/golib/v2/log"
)

func init() {
	o := new(GlobalConfigFacadeImpl)
	spring.Register(o, "GlobalConfigFacade", []*spring.PluginExtension{
		{
			Interface: "header.Service",
		},
	})
}

type GlobalConfigFacadeImpl struct {
	Bus        cloudbus.CloudBus              `autowire:"CloudBusImpl3"` // == zstackgo/pkg/core/cloudbus/cloudbus.CloudBusImpl3:CloudBusImpl3
	Dbf        db.DatabaseFacade              `autowire:"DatabaseFacadeImpl"`
	Errf       errorcode.ErrorFacade          `autowire:"ErrorFacadeImpl"`
	PluginRgty componentloader.PluginRegistry `autowire:"PluginRegistry"`
	AllConfig  sync.Map                       // map[string]*GlobalConfig
}

func (impl *GlobalConfigFacadeImpl) Start() error {
	initializer := &GlobalConfigInitializer{
		globalConfigFacadeImpl: impl,
		ConfigsFromXml:         make(map[string]*GlobalConfig),
		ConfigsFromDatabase:    make(map[string]*GlobalConfig),
		GlobalConfigFields:     make([]interface{}, 0),
		PropertiesMap:          make(map[string]string),
	}
	initializer.Init()

	return nil
}

func (impl *GlobalConfigFacadeImpl) Stop() error {
	return nil
}

type GlobalConfigInitializer struct {
	globalConfigFacadeImpl *GlobalConfigFacadeImpl
	ConfigsFromXml         map[string]*GlobalConfig
	ConfigsFromDatabase    map[string]*GlobalConfig
	GlobalConfigFields     []interface{}
	PropertiesMap          map[string]string
}

func (initializer *GlobalConfigInitializer) Init() {
	// todo lock
	initializer.LoadSystemProperties()
	initializer.ParseGlobalConfigFields()
	initializer.LoadConfigFromXml()
	initializer.LoadConfigFromJava()
	initializer.LoadConfigFromAutoGeneration()
	initializer.LoadConfigFromDatabase()
	initializer.CreateValidatorForBothXmlAndDatabase()
	initializer.ValidateConfigFromXml()
	initializer.ValidateConfigFromDatabase()
	initializer.PersistConfigInXmlButNotInDatabase()
	initializer.MergeXmlDatabase()
	initializer.Link()
	initializer.InitAllConfig()
	for k, v := range initializer.ConfigsFromXml {
		initializer.globalConfigFacadeImpl.AllConfig.Store(k, v)
	}
	//  re-validate after merging xml's with db's
	initializer.ValidateAll()
}

func (initializer *GlobalConfigInitializer) LoadSystemProperties() {
	keys := java.SystemProps.Section("").Keys()

	for _, k := range keys {
		initializer.PropertiesMap[k.Name()] = k.Value()
	}
}

func (initializer *GlobalConfigInitializer) ParseGlobalConfigFields() {
	// 1. 找到使用了GlobalConfigDefinition注解的类, 遍历其字段
	// 2. 如果该类字段定义包含static且通过isAssignableFrom()判断是否可转为GlobalConfig, 如果是则指示该反射的对象(字段)在使用时应该取消 Java 语言访问检查即可修改并将该字段放入globalConfigFields
}

func (initializer *GlobalConfigInitializer) LoadConfigFromXml() {
	// 通过JAXBContext.newInstance("org.zstack.core.config.schema")加载配置, 比如test/target/test-classes/globalConfig/*.xml
	// 将解析成GlobalConfig的配置放入configsFromXml
}

func (initializer *GlobalConfigInitializer) LoadConfigFromJava() {
	// 将ParseGlobalConfigFields()找到的fileds转为GlobalConfig并放入configsFromXml, 放入前需检查是否重复
}

func (initializer *GlobalConfigInitializer) LoadConfigFromAutoGeneration() {
	// 从实现了GlobalConfigInitExtensionPoint接口的实例上获取GlobalConfig并放入ConfigsFromXml
	exts := initializer.globalConfigFacadeImpl.PluginRgty.GetExtensionList("core.config.GlobalConfigInitExtensionPoint")
	for _, v := range exts {
		er := v.(GlobalConfigInitExtensionPoint)
		tmp := er.GetGenerationGlobalConfig()

		for _, v := range tmp {
			initializer.ConfigsFromXml[v.GetIdentity()] = v
		}
	}
}

func (initializer *GlobalConfigInitializer) LoadConfigFromDatabase() {
	// 从db获取GlobalConfig并放入configsFromDatabase
	//todo
}

func (initializer *GlobalConfigInitializer) CreateValidatorForBothXmlAndDatabase() {

}

func (initializer *GlobalConfigInitializer) ValidateConfigFromDatabase() {
	log.Glog.Debug("validating global config loaded from database")

	// 验证GlobalConfig
}

func (initializer *GlobalConfigInitializer) ValidateConfigFromXml() {
	log.Glog.Debug("validating global config loaded from XML files")

	// 验证GlobalConfig
}

func (initializer *GlobalConfigInitializer) PersistConfigInXmlButNotInDatabase() {
	// 持久化配置
}

func (initializer *GlobalConfigInitializer) MergeXmlDatabase() {
	// 将configsFromDatabase同步到configsFromXml
}

func (initializer *GlobalConfigInitializer) Link() {
	// globalConfigFields中的字段关联到GlobalConfig
}

func (initializer *GlobalConfigInitializer) InitAllConfig() {
	for _, config := range initializer.ConfigsFromXml {
		config.Init()
	}
}

func (initializer *GlobalConfigInitializer) ValidateAll() {
	// globalConfigFields中的字段关联到GlobalConfig
}
